package com.bizmda.bizsip.sink.connector;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONObject;
import com.bizmda.bizsip.common.BizException;
import com.bizmda.bizsip.common.BizResultEnum;
import com.bizmda.bizsip.common.BizUtils;
import com.bizmda.bizsip.config.AbstractSinkConfig;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 史正烨
 */
@Slf4j
public class BeanSinkConnector extends AbstractSinkConnector {
    private String clazzName = null;
    private String methodName = null;
    private boolean isSpringBean = false;
    private Map<String, Object> clazzMap = new HashMap<>();

    @Override
    public void init(AbstractSinkConfig sinkConfig) throws BizException {
        super.init(sinkConfig);
        this.clazzName = (String) sinkConfig.getConnectorMap().get("class-name");
        this.methodName = (String) sinkConfig.getConnectorMap().get("method-name");
        if (sinkConfig.getConnectorMap().get("spring-bean") == null) {
            this.isSpringBean = false;
        }
        else {
            this.isSpringBean = (Boolean) sinkConfig.getConnectorMap().get("spring-bean");
        }
        log.info("装载JavaApiSinkConnector参数:SpringBean[{}],class-name[{}],method-name[{}]",
                this.isSpringBean, this.clazzName, this.methodName);
    }

    @Override
    public Object process(Object inMessage) throws BizException {
        JSONObject jsonObject = (JSONObject) inMessage;
        String jsonClazzName;
        if (this.clazzName == null) {
            jsonClazzName = (String) jsonObject.get("className");
        }
        else {
            jsonClazzName = this.clazzName;
        }

        String jsonMethodName;
        if (this.methodName == null) {
            jsonMethodName = (String) jsonObject.get("methodName");
        }
        else {
            jsonMethodName = this.methodName;
        }

        if (jsonClazzName == null) {
            throw new BizException(BizResultEnum.OTHER_JAVA_CLASS_METHOD_ERROR,"类名为NULL");
        }

        if (jsonMethodName == null) {
            throw new BizException(BizResultEnum.OTHER_JAVA_CLASS_METHOD_ERROR,"方法名为NULL");
        }
        log.debug("调用JavaApiSinkConnector:{}.{}()", jsonClazzName, jsonMethodName);
        Object clazz;
        clazz = this.clazzMap.get(jsonClazzName);
        if (clazz == null) {
            try {
                if (isSpringBean) {
                    clazz = SpringUtil.getBean(Class.forName(jsonClazzName));
                } else {
                    clazz = Class.forName(jsonClazzName).getDeclaredConstructor().newInstance();
                }
            } catch (InstantiationException | IllegalAccessException | ClassNotFoundException
                    | NoSuchMethodException | InvocationTargetException e) {
                log.error("获取类出错",e);
                throw new BizException(BizResultEnum.CONNECTOR_JAVA_CLASS_CREATE_ERROR, e);
            }
            this.clazzMap.put(jsonClazzName, clazz);
        }
        Method method;
        try {
            method = ReflectUtil.getMethodByName(Class.forName(jsonClazzName), jsonMethodName);
        } catch (ClassNotFoundException e) {
            throw new BizException(BizResultEnum.CONNECTOR_JAVA_CLASS_CREATE_ERROR, e);
        }
        Object returnValue;
        try {
            Object args[] = BizUtils.JsonObject2MethodParameters(method,jsonObject.get("params"),(JSONObject)jsonObject.get("paramsTypes"));
            if (method.getParameterCount() == 0) {
                returnValue = method.invoke(clazz);
            }
            else if (method.getParameterCount() == 1) {
                returnValue = method.invoke(clazz, args[0]);
            }
            else {
                returnValue = method.invoke(clazz, args);
            }
        } catch (IllegalAccessException e) {
            log.error("执行类方法出错",e);
            throw new BizException(BizResultEnum.OTHER_JAVA_CLASS_METHOD_ERROR, e);
        } catch ( InvocationTargetException e) {
            Throwable t = e.getTargetException();
            if (t instanceof BizException) {
                throw (BizException) t;
            }            else if (t instanceof UndeclaredThrowableException) {
                Throwable t1 = ((UndeclaredThrowableException) t).getUndeclaredThrowable();
                if (t1 instanceof BizException) {
                    throw (BizException) t1;
                }
            }
            log.error("执行方法出错",e);
            throw new BizException(BizResultEnum.OTHER_JAVA_CLASS_METHOD_ERROR,e);
        }

        byte[] outMessage = null;
        JSONObject jsonObject1 = new JSONObject();

        jsonObject1.set("result",BizUtils.methodReturnBean2Json(returnValue));

//        outMessage = BizUtils.getBytes(JSONUtil.toJsonStr(jsonObject1));

        return jsonObject1;
    }
}
